﻿#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#include <stack>
#include "Cell.hpp"

Cell map[10][10];

bool Select;
int srow, sline;
int space = 100;

void init();
void clearMap();
bool add();
bool remove(int line, int row);
void move(int line1, int row1, int line2, int row2);
bool update();
bool hasEnd();
void draw();

int main() {
	initgraph(600, 720);
	srand(time(0));
	while (true) {
		init();
		while (true) {
			if (!update())
				break;
			draw();
		}
	}
	// 关闭图形窗口
	EndBatchDraw();
	closegraph();
	return 0;
}

void init() {
	setbkcolor(BROWN);
	clearMap();
	BeginBatchDraw();
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			map[i][j] = Cell(i, j);
	add();
}

void clearMap() {
	for (auto& i : map)
		for (auto& j : i)
			j.setColor(BLACK);
	Select = false;
}

bool add() {
	COLORREF colors[6] = { BLUE, GREEN, WHITE, RED, YELLOW, CYAN };
	int remain = space;
	int need = 3;
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			if (map[i][j].getColor() == BLACK) {
				if (remain && rand() % remain < need) {
					map[i][j].setColor(colors[rand() % 6]);
					need--;
					if (remove(i, j))
						space++;
				}
				remain--;
			}
		}
	}
	space -= 3;
	if (space <= 0)
		return false;
	return true;
}

bool remove(int line, int row)
{
	// 检测
	int cnt[3][3];
	COLORREF tmpColor = map[line][row].getColor();
	std::pair<int, int> dir = { -1, -1 };
	std::pair<int, int> tmpLocation;
	while (dir.first < 2) {
		tmpLocation = { line, row };
		tmpLocation.first += dir.first;
		tmpLocation.second += dir.second;
		if (dir.first != 0 || dir.second != 0) {
			cnt[1 + dir.first][1 + dir.second] = 0;
			while (tmpLocation.first >= 0 && tmpLocation.first < 10 &&
				tmpLocation.second >= 0 && tmpLocation.second < 10 &&
				map[tmpLocation.first][tmpLocation.second].getColor() == tmpColor) {
				tmpLocation.first += dir.first;
				tmpLocation.second += dir.second;
				cnt[1 + dir.first][1 + dir.second]++;
			}
		}
		dir.second++;
		if (dir.second == 2) {
			dir.second = -1;
			dir.first++;
		}
	}

	bool isRemove = false;

	// 消除
	// 左右
	if (cnt[1][0] + cnt[1][2] >= 4) {
		space += cnt[1][0] + cnt[1][2];
		isRemove = true;
		map[line][row].setColor(BLACK);
		tmpLocation = { line, row };
		dir = { 0, -1 };
		for (int i = 0; i < cnt[1][0]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
		tmpLocation = { line, row };
		dir = { 0, 1 };
		for (int i = 0; i < cnt[1][2]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
	}

	// 上下
	if (cnt[0][1] + cnt[2][1] >= 4) {
		space += cnt[0][1] + cnt[2][1];
		isRemove = true;
		map[line][row].setColor(BLACK);
		tmpLocation = { line, row };
		dir = { -1, 0 };
		for (int i = 0; i < cnt[0][1]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
		tmpLocation = { line, row };
		dir = { 1, 0 };
		for (int i = 0; i < cnt[2][1]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
	}

	// 左对角
	if (cnt[0][0] + cnt[2][2] >= 4) {
		space += cnt[0][0] + cnt[2][2];
		isRemove = true;
		map[line][row].setColor(BLACK);
		tmpLocation = { line, row };
		dir = { -1, -1 };
		for (int i = 0; i < cnt[0][0]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
		tmpLocation = { line, row };
		dir = { 1, 1 };
		for (int i = 0; i < cnt[2][2]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
	}

	// 右对角
	if (cnt[0][2] + cnt[2][0] >= 4) {
		space += cnt[0][2] + cnt[2][0];
		isRemove = true;
		map[line][row].setColor(BLACK);
		tmpLocation = { line, row };
		dir = { -1, 1 };
		for (int i = 0; i < cnt[0][2]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
		tmpLocation = { line, row };
		dir = { 1, -1 };
		for (int i = 0; i < cnt[2][0]; i++) {
			tmpLocation.first += dir.first;
			tmpLocation.second += dir.second;
			map[tmpLocation.first][tmpLocation.second].setColor(BLACK);
		}
	}

	return isRemove;
}

int checkMatrix[10][10];
void move(int line1, int row1, int line2, int row2) {
	if (map[line1][row1].getColor() == BLACK)
		return;
	if (map[line2][row2].getColor() != BLACK)
		return;

	constexpr int flagBit = 1 << 31;
	enum { blank = flagBit | 0, hold = flagBit | 1 };
	// initial matrix，先初始化判断矩阵
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++) {
			if (map[i][j].getColor() == BLACK) {
				checkMatrix[i][j] = blank;
			}
			else {
				checkMatrix[i][j] = hold;
			}
		}

	int checkNow = 0;
	bool flag = true;
	checkMatrix[line1][row1] = checkNow;
	while (flag) {
		flag = false;
		for (int i = 0; i < 10; i++)
			for (int j = 0; j < 10; j++) {
				if (checkMatrix[i][j] == checkNow) {
					flag = true;
					for (int line = i - 1; line <= i + 1; line++)
						for (int row = j - 1; row <= j + 1; row++) {
							if (line < 0 || line >= 10)
								continue;
							if (row < 0 || row >= 10)
								continue;
							if (checkMatrix[line][row] != blank)
								continue;
							if (line != i && row != j)
								continue;
							checkMatrix[line][row] = checkNow + 1;
						}
				}
			}
		checkNow++;
		if (checkMatrix[line2][row2] != blank)
			break;
	} // while (flag)

	if (checkMatrix[line2][row2] != blank) {
		std::stack<std::pair<int, int>> stk;
		stk.push({ line2, row2 });
		while (--checkNow) {
			int i = stk.top().first;
			int j = stk.top().second;
			for (int line = i - 1; line <= i + 1; line++)
				for (int row = j - 1; row <= j + 1; row++) {
					if (line < 0 || line >= 10)
						continue;
					if (row < 0 || row >= 10)
						continue;
					if (line != i && row != j)
						continue;
					if (checkMatrix[line][row] == checkNow) {
						stk.push({ line, row });
						goto out;
					}
				}
		out:
			;
		}

		// 开始移动
		Select = false;
		map[sline][srow].select(false);
		const COLORREF tmpColor = map[sline][srow].getColor();
		while (!stk.empty()) {
			map[sline][srow].setColor(BLACK);
			sline = stk.top().first;
			srow = stk.top().second;
			map[sline][srow].setColor(tmpColor);
			stk.pop();
			draw();
			Sleep(50);
		}

		// 添加
		if (!remove(line2, row2)) add();
		else space++;
	}
	else {
		Select = false;
		map[sline][srow].select(false);
	}
}

bool update() {
	ExMessage m;
	m = getmessage(EM_MOUSE);

	if (m.message == WM_LBUTTONUP) {
		int row = m.x / side;
		int line = m.y / side;
		line -= 2;
		if (row >= 0 && row < 10 && line >= 0 && line < 10) {
			if (map[line][row].getColor() != BLACK) {
				if (map[line][row].isSelect()) {// 该点已被选中
					Select = false;
					map[line][row].select(false);
				}
				else if (!map[line][row].isSelect()) {// 该点未被选中
					// 如果目前有被选中的点，需要先取消选中
					if (Select) {
						map[sline][srow].select(false);
					}
					Select = true;
					map[line][row].select(true);
					srow = row;
					sline = line;
				}
			}
			else if (Select) {
				Select = false;
				move(sline, srow, line, row);
			}
		}
	}
	else if (m.message == WM_RBUTTONUP && Select) {
		map[sline][srow].select(false);
		Select = false;
	}

	if (hasEnd()) return false;

	return true;
}

bool hasEnd() {
	for (int i : std::views::iota(0, 10))
		for (int j : std::views::iota(0, 10))
			if (map[i][j].getColor() == BLACK) return false;
	return true;
}

void draw() {
	cleardevice();
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++) {
			map[i][j].draw();
		}
	FlushBatchDraw();
}
